package Misil;

import Servidor.ServidorEnTierra;
import Utilidades.Logger;
import Misil.Comportamientos.*;
import Baterias.Bateria;
import Baterias.Monitor;

/**
 * @brief Clase que define a los misiles aliados.
 * @author Marcelo
 * @version 1.0
 * @created 17-jul-2012 09:08:36 p.m.
 */
public class MisilAliado extends Misil implements Runnable {

	private ServidorEnTierra m_ServidorEnTierra;
	private Monitor monitor;
	private Bateria bateriaAsignada;

	/**
	 * @brief For testing only
	 * @param posicion
	 *            de la bateria desde donde sera lanzado
	 */
	public MisilAliado(double[] posicion) {
		super();
		this.posicion = posicion;
		alineacionBelica = true;
		comportamiento = new EsperarASerLanzado();
		velocidad = 100;
	}

	/**
	 * @brief Constructor de la clase MisilAliado.
	 * @param posicion
	 *            de la bateria desde donde sera lanzado
	 * @param monitor
	 *            que gestiona el uso de las baterias
	 * @param Servidor
	 *            para poder sacar los datos del entorno
	 */
	public MisilAliado(Monitor monitor, ServidorEnTierra servidor,
			Bateria bateriaElegida) {
		super();
		alineacionBelica = true;
		this.posicion = bateriaElegida.getUbicacion();
		comportamiento = new EsperarASerLanzado();
		this.monitor = monitor;
		m_ServidorEnTierra = servidor;
		velocidad = 100;
		bateriaAsignada = bateriaElegida;
		generarID();
	}

	/**
	 * @brief Funcion que lanza al misil. Las baterias son las encargadas de
	 *        llamar a esta funcion para cambiar el patron de comportamiento del
	 *        misil de EsperarASerLanzado a Ascenso.
	 */
	public void serLanzado() {
		cambiarVuelo(1);
	}

	/**
	 * 
	 * @brief Los misiles aliados son hilos independientes. En este metodo,
	 *        solicitan ser disparados y, luego de que los disparen, ellos
	 *        mismos gestionan su movimiento. De igual manera, requieren Que el
	 *        entorno haga "pasar el tiempo" para poder desplazarse
	 */
	public void run() {
		try {

			monitor.solicitarBateria(this);

			// Tengo permiso para disparar => Disparo!
			bateriaAsignada.cargarMisil(this);
			bateriaAsignada.Disparar();

			System.out.println(ID + ": Lanzado desde [" + posicion[0] + ";"
					+ posicion[1] + ";" + posicion[2] + "]");
			Logger.escribir(ID + ": Lanzado desde [" + posicion[0] + ";"
					+ posicion[1] + ";" + posicion[2] + "]");

			while (!destruido) {
				if ((this.getComportamiento().getTipoMovimiento() == 1)
						&& (posicion[2] >= 100)) {
					// Si ascendio significa que ahora se tiene que posicionar
					this.cambiarVuelo(2);// Cambio a Posicionamiento
				}

				// Si alcanzo el punto por donde entrara el enemigo, estando en
				// la etapa de posicionamiento, cambio a DerechoAlChoque
				if ((this.getComportamiento().objetivoAlcanzado(this
						.getPosition()))
						&& (this.getComportamiento().getTipoMovimiento() == 2)) {
					posicion = (double[]) getComportamiento().getObjetivo();
					cambiarVuelo(3);
					// Tenemos que interceptar al enemigo para pegar
					InterceptarEnemigo();
					// Hay q medir la distancia entre los 2 para saber si le
					// pego.
				}

				// Si estamos interceptando al enemigo(derecho al choque)
				if (getComportamiento().getTipoMovimiento() == 3) {
					MisilEnemigo e1 = (MisilEnemigo) m_ServidorEnTierra
							.getMapeo().get(this);
					// Cambiamos el objetivo del aliado a medida que se mueve el
					// enemigo
					getComportamiento().setObjetivo(e1.getPosition());
					// Si lo intercepto destruimos ambos
					if (getComportamiento().objetivoAlcanzado(posicion)) {
						e1.explotar();
						this.explotar();
					}
				}

				try {
					Thread.sleep(250);// Dormir el misil
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @brief Funcion que cambia el comportamiento del vuelo del misil aliado.
	 *        Si el misil esta ascendiendo(1) pasa a Posicionarse(2), y si se
	 *        esta posicionando (2) pasa a ir derecho al choque(3)
	 */
	public void cambiarVuelo(int caso) {
		if (caso == 1) {// Esto lo hace la abteria al lanzar el misil
			ComportamientoMisilAliado comportamientoNuevo = new Ascenso(
					comportamiento.getObjetivo());
			comportamiento = comportamientoNuevo;
		}
		if (caso == 2) {// Esto pasa cuando pasa un segundo de que asendio en
						// volar()
			ComportamientoMisilAliado comportamientoNuevo = new Posicionamiento(
					comportamiento.getObjetivo(), this.getPosition());
			comportamiento = comportamientoNuevo;
		} else if (caso == 3) {
			ComportamientoMisilAliado comportamientoNuevo = new DerechoAlChoque(
					comportamiento.getObjetivo());
			comportamiento = comportamientoNuevo;
		}
	}

	/**
	 * @brief funcion que utilizamos despues de cambiar el comportamiento del
	 *        misil. El nuevo objetivo del comportamiento del misil debe ser la
	 *        posicion actual del enemigo La velocidad es la misma pero con el
	 *        signo cambiado
	 */
	public void InterceptarEnemigo() {
		MisilEnemigo e1 = (MisilEnemigo) m_ServidorEnTierra.getMapeo()
				.get(this);
		// Seteamos el objetivo, como la posicion del enemigo
		getComportamiento().setObjetivo(e1.getPosition());
		// Seteamos la velocidad
		double speed[] = e1.getComportamiento().getVectorDeVelocidad();
		speed = getComportamiento().invertirVelocidad(speed);
		getComportamiento().setVectorDeVelocidad(speed);

	}

	public int getIndiceBateria() {
		return bateriaAsignada.getIndice();
	}

}